<script lang="jsx">
/**
   * @example
    const searchOption = [
      { key: 'name', label: '姓名', type: 'input', defaultValue: 'xxx'},
      { key: 'sex', label: '性别', type: 'select', options: [{ label: '男', value: '1' }, { label: '女', value: '2' }]},
      { key: 'testCustom', label: '自定义', type: 'custom', component: CustomComponent}
    ]
    <SearchBar :searchOption="searchOption"></SearchBar>
  */
import { ref, useAttrs, useSlots } from "vue"
import { Search, Refresh } from "@element-plus/icons-vue"

export default {
  name: "SearchBar",
  props: {
    // 渲染配置
    searchOption: {
      type: Array,
      required: true,
      default: () => {
        return []
      }
    },
    title: {
      // 标题
      type: String,
      default: ""
    },
    useSearch: {
      // 是否显示搜索按钮
      type: Boolean,
      default: true
    },
    useReset: {
      // 是否显示重置按钮
      type: Boolean,
      default: true
    }
  },
  emits: ["handleSearch"],
  setup(props, { emit, expose }) {
    const slots = useSlots()
    // 表单数据
    const formData = ref({})

    let isMounted = false
    // 重置表单数据
    const handleReset = () => {
      const temp = {}
      props.searchOption.forEach(({ key, defaultValue, noReset = false }) => {
        // console.log('defaultValue', defaultValue);
        if (noReset) {
          temp[key] = formData.value?.[key] || defaultValue || ""
        } else {
          temp[key] = defaultValue || ""
        }
      })
      formData.value = temp
    }
    handleReset()

    const camelCase = (str) => {
      return str.replace(/-[a-z]/g, (str1) => str1.substr(-1).toUpperCase())
    }
    const handleSearch = () => {
      emit("handleSearch", formData.value)
    }

    // 根据类型渲染组件
    const componentsMap = {
      select: (itemProps, key) => {
        // console.log('select-itemProps', itemProps);
        const { options = [], optionFiled = {}, ...others } = itemProps

        return (
          <el-select onChange={handleSearch} v-model={formData.value[key]} placeholder="请选择" {...others}>
            {options.map((option) => {
              return (
                <el-option
                  key={option[optionFiled.value || "value"]}
                  label={option[optionFiled.label || "label"]}
                  value={option[optionFiled.value || "value"]}
                ></el-option>
              )
            })}
          </el-select>
        )
      },
      input: (itemProps, key) => {
        const attrs = {
          onChange: handleSearch,
          ...itemProps
        }
        return <el-input v-model={formData.value[key]} placeholder="请输入" {...attrs}></el-input>
      },
      datePicker: (itemProps, key) => {
        const attrs = {
          onChange: handleSearch,
          ...itemProps
        }
        return (
          <el-date-picker
            v-model={formData.value[key]}
            type="datetimerange"
            range-separator="至"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            {...attrs}
          />
        )
      },
      custom: (itemProps, key, CustomComponent) => {
        const attrs = {
          onChange: handleSearch,
          ...itemProps
        }

        return <CustomComponent v-model={formData.value[key]} {...attrs}></CustomComponent>
      }
    }

    const exposeHandleReset = () => {
      handleReset()
      emit("handleSearch", formData.value)
    }

    expose({
      formData,
      handleReset: exposeHandleReset
    })

    return () => (
      <div class="search-bar">
        {(slots.title || props.title) && (
          <div class="title-bar">
            {slots.title ? slots.title() : <div class="title">{props.title || ""}</div>}
            <div class="custom-btn">{slots.default?.()}</div>
          </div>
        )}
        <div class="search-bar-inner">
          <el-form inline={true} model={formData.value} class="demo-form-inline">
            {props.searchOption
              .filter((x) => x.vIf === undefined || x.vIf)
              .map((searchItem) => {
                const {
                  key,
                  label,
                  type,
                  options,
                  optionKey,
                  optionFiled,
                  useAll,
                  attrs = {}, // 直接透传到实际组件上的属性
                  component, // 自定义组件 使用
                  slotRender,
                  vShow
                } = searchItem

                // 额外的需要特殊处理的属性
                const otherAttrs = {
                  options,
                  optionKey,
                  optionFiled,
                  useAll
                }

                const formatType = camelCase(type)
                return formatType === "slot" ? (
                  slotRender()
                ) : (
                  <el-form-item label={label} key={key} prop={key} v-show={vShow === undefined || vShow}>
                    {componentsMap[formatType] && componentsMap[formatType](attrs, key, component, otherAttrs)}
                  </el-form-item>
                )
              })}
            {slots.otherItem?.()}

            {props.useSearch && (
              <el-form-item class="form-btn-group">
                <el-button type="primary" icon={Search} onClick={handleSearch}>
                  查&nbsp;询
                </el-button>
              </el-form-item>
            )}
            <el-form-item class="form-btn-group">
              <el-button icon={Refresh} onClick={exposeHandleReset}>
                重&nbsp;置
              </el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    )
  }
}
</script>

<style lang="scss" scoped>
.search-bar {
  // padding: 12px 0;
  background-color: #fff;
  border-bottom: 20px solid #f2f3f5;
  border-radius: none;
  .title-bar {
    padding: 0 12px;
    height: 48px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid #f5f5f5;
    margin-bottom: 8px;
    .title {
      margin-bottom: 0;
    }
  }
  .custom-btn {
    white-space: nowrap;
    flex-shrink: 0;
  }
}
.demo-form-inline {
  padding: 20px 20px 0;
  ::v-deep(.el-form-item) {
    margin-bottom: 20px;
  }
}
</style>
